package cn.edu.hznu.web.crawl;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;

public class CrawlByParseString {
	
	private String expressBooksPart, 
				   popularBooksPart,
				   ebooksPart;
	
	final static String FILEDIR = "/Users/LVZY/Documents/Record/Crawl/douban.com/";
	
	public void crawlDoubanIndexPage() {
		try {
			this.processSectionPart();
			this.processEbooksPart();
			this.processExpressBooksPart();
			this.processPopularBooksPart();
			this.processEbooksPart();
		} catch (ParseException | IOException e) {
			e.printStackTrace();
		}
	}

	public String getResponseBody() throws ClientProtocolException, ParseException, IOException {
		return DownloadContent.getStrContentFromUrl("http://book.douban.com/", "utf-8");
	}

	private void processSectionPart() throws ClientProtocolException, ParseException, IOException {
		String articlePart = this.getResponseBody()
								 .replaceAll("\\s", "")
								 .replaceFirst(".+?class=\"article\">", "")
								 .replaceFirst("(?:</?div>?){2}class=\"aside\".+>", "");
		
		String[] sectionsPart = articlePart.split("class=\"section");
		for (int i = 1; i < sectionsPart.length; i++) {
			if (sectionsPart[i].startsWith("books-express")) {
				this.expressBooksPart = sectionsPart[i];
			} else if (sectionsPart[i].startsWith("popular-books")) {
				this.popularBooksPart = sectionsPart[i];
			} else if (sectionsPart[i].startsWith("ebook-area")) {
				this.ebooksPart = sectionsPart[i];
			}
			System.out.println(sectionsPart[i]);
		}
	}

	private void processExpressBooksPart() {
		Pattern regExBookDetails = Pattern.compile("more-meta.+?"
									+ "title\">(.+?)<.+?"
									+ "author\">(.+?)<.+?"
									+ "year\">(.+?)<.+?"
									+ "publisher\">(.+?)<.+?"
									+ "abstract\">(.+?)<");
		Pattern regExBookImg = Pattern.compile("<imgsrc=\"(.+?)\".+?alt=\"(.+?)\"");
		Matcher m;
		File booksFolder = this.createFolder(FILEDIR + "books-express-temp/");

		// Cannot set charset
		// BufferedWriter bfWriter = new BufferedWriter(
		// 			new FileWriter("path"), bufferSize);
		
		// Can set charset
		// BufferedWriter bfWriter = new BufferedWriter(
		// 			new OutputStreamWriter(
		// 				new FileOutputStream("path"), "charset"));
		
		// Can set charset but not buffer
		// OutputStreamWriter writer = new OutputStreamWriter(
		//			new FileOutputStream("path"), "charset")
		
		try (BufferedWriter bfWriter = this.createBufferedWriter(
				booksFolder + "/books-details.txt", "UTF-8")) {
			String[] expressBookBlocks = this.expressBooksPart.split("<ul");
			for (int i = 1; i < expressBookBlocks.length; i++) {
				String[] expressBooks = expressBookBlocks[i].split("<li");
				for (int j = 1; j < expressBooks.length; j++) {
					m = regExBookDetails.matcher(expressBooks[j]);
					if (m.find()) {
						this.writeBookDetails(bfWriter, m, new String[]{
								"", "title", "author", "year", "publisher",
								"abstract"
						});
					}
					m = regExBookImg.matcher(expressBooks[j]);
					if (m.find()) {
						this.writeBookImg(booksFolder, m);
					}
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void processPopularBooksPart() {
		Pattern regExBookDetails = Pattern.compile("title\">.+?>(.+?)<.+?"
													+ "author\">(.+?)<.+?"
													+ "classification\">(.+?)<.+?"
													+ "reviews\">(.+?)<");
		Pattern regExBookImg = Pattern.compile("imgsrc=\"(.+?)\"alt=\"(.+?)\"");
		Matcher m;
		File booksFolder = this.createFolder(FILEDIR + "popular-books/");
		try (BufferedWriter bfWriter = this.createBufferedWriter(
				booksFolder + "/books-details.txt", "UTF-8")) {
			String[] popularBooksBlocks = this.popularBooksPart.split("<li");
			for (int i = 1; i < popularBooksBlocks.length; i++) {
				m = regExBookDetails.matcher(popularBooksBlocks[i]);
				if (m.find()) {
					this.writeBookDetails(bfWriter, m, new String[]{
							"", "title", "author", "classification", 
							"reviews"
					});
				}
				m = regExBookImg.matcher(popularBooksBlocks[i]);
				if (m.find()) {
					this.writeBookImg(booksFolder, m);
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void processEbooksPart() {
		Pattern regExBookDetails = Pattern.compile("more-meta.+?"
													+ "title\">(.+?)<.+?"
													+ "author\">(.+?)<.+?"
													+ "year\">(.+?)<.+?"
													+ "publisher\">(.+?)<.+?"
													+ "price\">(.+?)<.+?"
													+ "abstract\">(.+?)<");
		Pattern regExBookImg = Pattern.compile("imgsrc=\"(.+?)\"alt=\"(.+?)\"");
		Matcher m;
		File booksFolder = this.createFolder(FILEDIR + "ebooks/");
		try (BufferedWriter bfWriter = this.createBufferedWriter(
				booksFolder + "/ebooks.txt", "UTF-8")) {
			String[] ebooksBlocks = this.ebooksPart.split("<li");
			for (int i = 0; i < ebooksBlocks.length; i++) {
				m = regExBookDetails.matcher(ebooksBlocks[i]);
				if (m.find()) {
					this.writeBookDetails(bfWriter, m, new String[] {
							"", "title", "author", "year", 
							"publisher", "price", "abstract"
					});
				}
				m = regExBookImg.matcher(ebooksBlocks[i]);
				if (m.find()) {
					this.writeBookImg(booksFolder, m);
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void writeBookDetails(BufferedWriter bfWriter, Matcher m, String[] marker)
			throws IOException {
		for (int i = 1; i < marker.length; i++) {
			bfWriter.write(marker[i] + ": " + m.group(i));
			bfWriter.newLine();
		}
		bfWriter.newLine();
	}
	
	private void writeBookImg(File imgFloder, Matcher m)
			throws FileNotFoundException, IOException {
		try (BufferedOutputStream bfOutStream = new BufferedOutputStream(
				new FileOutputStream(
						new File(imgFloder, m.group(2) + ".jpg")))) {
			DownloadContent.downloadImgFromUrl(m.group(1), bfOutStream);
		}
	}
	
	@SuppressWarnings("unused")
	private void writeBookImg2(File imgFloder, Matcher m)
			throws FileNotFoundException, IOException {
		try (BufferedOutputStream bfOutStream = new BufferedOutputStream(
				new FileOutputStream(
						new File(imgFloder, m.group(2) + ".jpg")))) {
			bfOutStream.write(DownloadContent
					.getByteContentFromUrl(m.group(1)));
		}
	}
	
	private File createFolder(String folderName) {
		File folder = new File(folderName);
		if (!folder.exists()) {
			folder.mkdirs();
		}
		return folder;
	}

	private BufferedWriter createBufferedWriter(String filename, String charset)
			throws UnsupportedEncodingException, FileNotFoundException {
		return new BufferedWriter(
				new OutputStreamWriter(
						new FileOutputStream(
								new File(filename)), charset));
	}
	
	// Using same output stream to write to different files ?
}
